package ml.practicum.table;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
 * Implements a Headed table that can scale up dynamically and has extra methods
 * to do so properly
 * 
 * @author Joscha
 *
 * @param <H> Head type
 * @param <T> Table data type
 */

public class DynamicHeadedTable<H,T> implements HeadedTable<H,T> {
	List<H> tableHeader;
	List<List<T>> tableBody;
	
	@SuppressWarnings("unchecked")
	public DynamicHeadedTable(List<H> header){
		this((H[]) header.toArray());
	}
	
	public DynamicHeadedTable(H[] header){
		setHeader(header);
		tableBody = new ArrayList<List<T>>();
	}
	@SuppressWarnings("unchecked")
	public DynamicHeadedTable(H header){
		H[] headerArray = (H[]) new Object[1];
		headerArray[0]= header;
		setHeader(headerArray);
		tableBody = new ArrayList<List<T>>();
	}
	
	@SuppressWarnings("unchecked")
	public DynamicHeadedTable(int columns){
		this((H[]) new Object[columns]);
	}
	
	public void addColumn(T[] newColumn, H label){
		if (newColumn.length == getRowCount()){
			tableHeader.add(label);
			for(int i = 0; i<getRowCount(); i++) {
				tableBody.get(i).add(newColumn[i]);
			}
		} else{
			throw new IndexOutOfBoundsException("Size of the new column is not equal to the number of rows");
		}
	}

	public void addRow(T[] newRow){
		if (newRow.length == getColumnCount()){
			tableBody.add(new ArrayList<T>(Arrays.asList(newRow)));
		} else{
			throw new IndexOutOfBoundsException("Size of the new row is not equal to the number of columns");
		}
	}


	public List<T> getColumn(int index) {
		ArrayList<T> result = new ArrayList<T>();
		for(List<T> row:tableBody){
			result.add(row.get(index));
		}
		return result;
	}

	public T getField(int row, int column) {
		return tableBody.get(row).get(column);
	}

	public List<H> getHeader() {
		return tableHeader;
	}

	public H getLabel(int row) {
		return tableHeader.get(row);
	}

	public List<T> getRow(int index) {
		return tableBody.get(index);
	}

	public void setColumn(int index, T[] column) {
		for(int i = 0; i < getRowCount(); i++){
			tableBody.get(i).set(index, column[i]);
		}
	}

	public void setField(int row, int column, T field) {
		tableBody.get(row).set(column, field);
	}

	public void setLabel(int row, H label) {
		tableHeader.set(row, label);
	}

	public void setRow(int index, T[] row) {
		if (row.length == getColumnCount()){
			tableBody.set(index, new ArrayList<T>(Arrays.asList(row)));
		}else{ 
			throw new IndexOutOfBoundsException();
		}
	}

	public void setHeader(H[] header) {
		tableHeader = new ArrayList<H>(Arrays.asList(header));
	}

	public int getRowCount(){
		return tableBody.size();
	}
	
	public int getColumnCount(){
		return tableHeader.size();
	}
	
	public List<List<T>> getRows() {
		return tableBody;
	}
	
	public void setRows(List<List<T>> input){
		tableBody =input; 
	}
	
	public List<List<T>> getColumns() {
		List<List<T>> result = new ArrayList<List<T>>();
		for(int i = 0; i< getColumnCount(); i++){
			result.add(getColumn(i));
		}
		return result;
	}
	
	public String toString(){
		StringBuffer result = new StringBuffer();
		result.append("{");
		result.append(getHeader().toString());
		result.append("\n");
		for (List<T> row:getRows()){
			result.append(row.toString());
			result.append("\n");
		}
		result.append("}");
		return result.toString();
	}
}
